package com.sxjh.service.impl;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.resource.InputStreamResource;
import cn.hutool.core.io.resource.MultiResource;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.sxjh.common.ResultException;
import com.sxjh.entity.ConfigEntity;
import com.sxjh.entity.File;
import com.sxjh.entity.result.PhpUpLoadResult;
import com.sxjh.mapper.FileMapper;
import com.sxjh.service.FileService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.FileSystemResource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.CompletableFuture;

@Service
public class FileServiceImpl extends ServiceImpl<FileMapper, File> implements FileService {

    @Autowired
    private ConfigEntity configEntity;

    @Autowired
    private FileMapper fileMapper;

    @Transactional(rollbackFor = Exception.class)
    @Override
    public String saveFile(MultipartFile file) throws Exception {
        // 获取文件最终保存路径和名称
        String uuid = IdUtil.simpleUUID();
        // 查询最新的子目录
        String maxDir = fileMapper.getSubdirectory();
        if (StrUtil.isEmpty(maxDir)) maxDir = "/0";
        // 查询子目录当前已存储多少个文件
        Integer count = fileMapper.getDirCount(maxDir);
        // 子目录达到存储最大数量，创建下一个子目录
        if (count == configEntity.getFileMax()) {
            String dir = maxDir.substring(1, maxDir.length());
            Integer dirNumber = Integer.parseInt(dir);
            dirNumber++;
            maxDir = "/" + dirNumber;
        }
        String savePath = getFolder(maxDir) + "/" + uuid;
        // 获取文件后缀
        String fileName = file.getOriginalFilename();
        int begin = StrUtil.lastIndexOfIgnoreCase(fileName, ".");
        String name = StrUtil.sub(fileName, begin, fileName.length());
        // 保存文件信息
        File entity = new File();
        entity.setCode(uuid);
        entity.setName(fileName);
        entity.setDir(maxDir);
        entity.setSuffix(name);
        save(entity);
        // 保存文件
        java.io.File file1 = new java.io.File(savePath);
        file.transferTo(file1);
        return uuid;
    }

    @Override
    public ResponseEntity download(String code) throws RuntimeException {
        // 查询文件信息
        File entity = getOne(new LambdaQueryWrapper<File>().eq(File::getCode, code));
        if (entity == null) return ResponseEntity.ok("文件不存在");
        // 获取文件路径，名称
        String fileName = getFolder();
        java.io.File file = new java.io.File(fileName + entity.getDir() + "/" + code);
        HttpHeaders headers = new HttpHeaders();
        headers.add("Cache-Control", "no-cache, no-store, must-revalidate");
        headers.add("Content-Disposition", "attachment; filename=" + code + entity.getSuffix());
        headers.add("Pragma", "no-cache");
        headers.add("Expires", "0");
        headers.add("Last-Modified", LocalDateTime.now().toString());
        headers.add("ETag", String.valueOf(System.currentTimeMillis()));
        return ResponseEntity.ok().headers(headers).contentLength(file.length()).contentType(MediaType.parseMediaType("application/octet-stream")).body(new FileSystemResource(file));
    }

    @Override
    @Async(value = "taskExecutor")
    public CompletableFuture<String> savePhpFile(MultipartFile file) throws ResultException, IOException {
        String url = configEntity.getAddress() + "/api/fileUpload";
        Map<String, String> headers = new HashMap<>();
        headers.put("Content-Type", "multipart/form-data");
        MultiResource multiResource = new MultiResource(new InputStreamResource(file.getInputStream(), file.getOriginalFilename()));
        String result = HttpUtil.createPost(url).addHeaders(headers).timeout(100000).form("file", multiResource).execute().body();
        if (StrUtil.isBlank(result)) {
            return CompletableFuture.completedFuture(null);
        }
        PhpUpLoadResult phpUpLoadResult = JSON.parseObject(result, PhpUpLoadResult.class);
        if (phpUpLoadResult != null) {
            PhpUpLoadResult.Status status = phpUpLoadResult.getStatus();
            if (status != null && status.getErrCode() == 0) {
                PhpUpLoadResult.Data data = phpUpLoadResult.getData();
                if (data != null) {
                    return CompletableFuture.completedFuture("/storage/uploadfile/" + data.getPath());
                }
            } else {
                throw new ResultException(status.getMessage());
            }
        }
        return CompletableFuture.completedFuture(null);
    }

    /**
     * 创建文件保存目录，并返回
     *
     * @param maxDir 最新的子目录
     * @return 最终保存的目录
     */
    public String getFolder(String maxDir) {
        // 获取保存文件目录
        String folder = configEntity.getFolder();
        String startFolder = folder.substring(0, 1);
        String startFolder2 = folder.substring(1, 2);
        // 相对路径拼接
        if (!"/".equals(startFolder) && !":".equals(startFolder2)) {
            // 去掉相对路径前./
            String startFolder3 = folder.substring(0, 2);
            if ("./".equals(startFolder3)) folder = folder.substring(2);
            // 相对路径拼接为绝对路径
            String src = System.getProperty("user.dir");
            folder = src + "/" + folder;
        }
        FileUtil.mkdir(folder + maxDir);
        return folder + maxDir;
    }

    /**
     * 创建文件保存目录，并返回
     *
     * @return 最终的父目录
     */
    public String getFolder() {
        // 获取保存文件目录
        String folder = configEntity.getFolder();
        String startFolder = folder.substring(0, 1);
        String startFolder2 = folder.substring(1, 2);
        // 相对路径拼接
        if (!"/".equals(startFolder) && !":".equals(startFolder2)) {
            // 去掉相对路径前./
            String startFolder3 = folder.substring(0, 2);
            if ("./".equals(startFolder3)) folder = folder.substring(2);
            // 相对路径拼接为绝对路径
            String src = System.getProperty("user.dir");
            folder = src + "/" + folder;
        }
        return folder;
    }

}
